﻿using System;
using System.Collections.Generic;
using NHibernate.Mapping.ByCode;
using Xenta.Enums;

namespace Xenta.Entities
{
    /// <summary>
    /// Represents the file meta entity.
    /// </summary>
    /// <remarks><pre>
    /// The entity regarding the disclosure level.
    /// 
    /// + Entire
    ///  + Extended
    ///   + Base
    ///    | - StorageID
    ///    | - Owner(of the Base level)
    ///    | - Folder(of the Primary level)
    ///    | - Name
    ///    | - MimeType
    ///    | - Size
    ///    | - Flags
    ///    | - UpdatedOn
    ///    | - CreatedOn
    ///    + Keys
    ///     | - Guid
    ///     + Primary
    ///      | - EntityID
    /// 
    /// Note: upper level includes lower level.
    /// </pre></remarks>
    public class FileEntity : AuditableEntity
    {
        #region Fields

        private FileFolderEntity _folder;
        private ICollection<FileGroupEntity> _groups;

        #endregion

        #region Ctors

        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public FileEntity()
        {
            _folder = null;
            _groups = new List<FileGroupEntity>();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the file storage global unique identifier.
        /// </summary>
        public virtual Guid StorageID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the global unique identifier.
        /// </summary>
        public virtual Guid Guid
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the owner.
        /// </summary>
        public virtual FileOwnerEntity Owner
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the folder identifier.
        /// </summary>
        public virtual int FolderID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the folder.
        /// </summary>
        public virtual FileFolderEntity Folder
        {
            get
            {
                return FolderID != 0 ? _folder : null;
            }
            set
            {
                _folder = value;
                FolderID = value == null ? 0 : value.EntityID;
            }
        }

        /// <summary>
        /// Gets or sets the file name.
        /// </summary>
        public virtual string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the MIME type.
        /// </summary>
        public virtual string MimeType
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the size.
        /// </summary>
        public virtual long Size
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the flags.
        /// </summary>
        public virtual FileFlags Flags
        {
            get;
            set;
        }

        #endregion

        #region Collections

        /// <summary>
        /// Gets or sets the group collection.
        /// </summary>
        public virtual ICollection<FileGroupEntity> Groups
        {
            get
            {
                return _groups;
            }
            set
            {
                _groups = value;
            }
        }

        #endregion

        #region Utilities

        protected override void Disclose(IDictionary<String, Object> obj,
            DisclosureLevel level,
            IDictionary<String, String> options)
        {
            base.Disclose(obj, level, options);
            if(level >= DisclosureLevel.Keys)
                obj["Guid"] = Guid;
            if(level >= DisclosureLevel.Base)
            {
                obj["StorageID"] = StorageID;
                obj["Owner"] = Owner.Disclose(DisclosureLevel.Base, options);
                obj["Folder"] = Folder != null
                    ? Folder.Disclose(DisclosureLevel.Primary, options)
                    : null;
                obj["Name"] = Name;
                obj["MimeType"] = MimeType;
                obj["Size"] = Size;
                obj["Flags"] = Flags.ToString();
            }
        }

        #endregion
    }

    /// <summary>
    /// The entity NHibernate mapping.
    /// </summary>
    public class FileMapping : EntityMapping<FileEntity>
    {
        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public FileMapping()
        {
            Table("fwk_Files");
            Id(x => x.EntityID, m =>
            {
                m.Column("FileID");
                m.Generator(Generators.Identity);
            });
            Property(x => x.StorageID, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.Guid, m =>
            {
                m.Unique(true);
                m.Index("IX_fwk_Files");
                m.NotNullable(true);
            });
            ManyToOne(x => x.Owner, m =>
            {
                m.Column("OwnerID");
                m.ForeignKey("FK_fwk_Files_fwk_FileOwners");
                m.NotNullable(true);
                m.Fetch(FetchKind.Join);
            });
            Property(x => x.FolderID, m =>
            {
                m.Column("FolderID");
                m.NotNullable(true);
            });
            ManyToOne(x => x.Folder, m =>
            {
                m.Column("FolderID");
                m.NotFound(NotFoundMode.Ignore);
                m.Insert(false);
                m.Update(false);
            });
            Property(x => x.Name, m =>
            {
                m.NotNullable(true);
                m.Length(100);
                m.Column(c =>
                {
                    c.SqlType("nvarchar(100)");
                });
            });
            Property(x => x.MimeType, m =>
            {
                m.NotNullable(true);
                m.Length(100);
                m.Column(c =>
                {
                    c.SqlType("nvarchar(100)");
                });
            });
            Property(x => x.Size, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.Flags, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.CreatedOn, m =>
            {
                m.NotNullable(true);
            });
            Property(x => x.UpdatedOn, m =>
            {
                m.NotNullable(true);
            });
            Bag(x => x.Groups, m =>
            {
                m.Table("fwk_MFileGroups");
                m.Key(k =>
                {
                    k.Column("FileID");
                    k.ForeignKey("FK_fwk_MFileGroups_fwk_Files");
                    k.NotNullable(true);
                });
                m.Inverse(true);
            },
            a =>
            {
                a.ManyToMany(m =>
                {
                    m.Column("GroupID");
                    m.ForeignKey("FK_fwk_MFileGroups_fwk_FileGroups");
                });
            });
        }
    }
}
